/* Audio passthru

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/

#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "audio_pipeline.h"
#include "i2s_stream.h"
#include "equalizer.h"
#include "filter_resample.h"

#include "board.h"

#include "record_filter.h"
#include "iStetho3_util.h"
#include "u8g2_esp32.h"

static const char *TAG = "istetho3_audio";

//  *        Different sample rates support different EQ frequency bands. 
//  *         11025:        {31, 62, 125, 250, 500, 1000, 2000, 3000, 4000, 5500}
//  *         22050:        {31, 62, 125, 250, 500, 1000, 2000, 4000, 8000, 11000}
//  *         44100/48000:  {31, 62, 125, 250, 500, 1000, 2000, 4000, 8000, 16000}

//  *Freq     {  31,  62, 125, 250, 500,1000,2000,4000,8000,16000, 31,  62, 125, 250, 500,1000,2000,4000,8000,16000}
int gainA[] = { -13, -13,  12, -13, -13, -13, -13, -13, -13, -13, -13, -13,  12, -13, -13, -13, -13, -13, -13, -13}; // 心音
int gainB[] = { -13, -13,   6,  14, -13, -13, -13, -13, -13, -13, -13, -13,   6,  14, -13, -13, -13, -13, -13, -13}; // 肺音
int gainC[] = { -13, -13,  10,  10,   0, -13, -13, -13, -13, -13, -13, -13,  10,  10,   0, -13, -13, -13, -13, -13}; // 心肺音

mode_type_t g_mode = MODE_Filter_A;
uint8_t     g_volume = 80;
bool        g_busy = false;
uint8_t     g_language = 0;  
uint8_t     g_bat_level = 5;

void audio_task(void)
{
    int  iSampleRate = 8000; 
    audio_pipeline_handle_t pipeline;
    audio_element_handle_t i2s_stream_writer, i2s_stream_reader;
    audio_element_handle_t equalizer, resampler, record_filter;

    ESP_LOGI(TAG, "[ 1 ] Start codec chip");
    audio_board_handle_t board_handle = audio_board_init();
    audio_hal_ctrl_codec(board_handle->audio_hal, AUDIO_HAL_CODEC_MODE_BOTH, AUDIO_HAL_CTRL_START);

    ESP_LOGI(TAG, "[ 2 ] Create audio pipeline for playback");
    audio_pipeline_cfg_t pipeline_cfg = DEFAULT_AUDIO_PIPELINE_CONFIG();
    pipeline = audio_pipeline_init(&pipeline_cfg);


    ESP_LOGI(TAG, "[3.1] Create i2s stream to read data from codec chip");
    i2s_stream_cfg_t i2s_cfg_read = I2S_STREAM_CFG_DEFAULT();
    i2s_cfg_read.type = AUDIO_STREAM_READER;
    i2s_cfg_read.std_cfg.clk_cfg.sample_rate_hz = iSampleRate;
    i2s_stream_reader = i2s_stream_init(&i2s_cfg_read);

    // ESP_LOGI(TAG, "[3.2] Create equalizer.");
    // equalizer_cfg_t eq_cfg = DEFAULT_EQUALIZER_CONFIG();
    // if(g_mode == MODE_Filter_A){
    //     eq_cfg.set_gain = gainA; 
    // }else if(g_mode == MODE_Filter_B){
    //     eq_cfg.set_gain = gainB; 
    // }else if(g_mode == MODE_Filter_C){
    //     eq_cfg.set_gain = gainC; 
    // }   
    // equalizer = equalizer_init(&eq_cfg);

    // ESP_LOGI(TAG, "[3.3] Create resampler.");
    // rsp_filter_cfg_t rsp_cfg = DEFAULT_RESAMPLE_FILTER_CONFIG();
    // rsp_cfg.src_rate = 48000;
    // rsp_cfg.src_ch = 2;
    // rsp_cfg.dest_rate = 8000;
    // rsp_cfg.dest_ch = 2;
    // rsp_cfg.mode = RESAMPLE_ENCODE_MODE;
    // rsp_cfg.complexity = 0;
    // resampler = rsp_filter_init(&rsp_cfg);

    ESP_LOGI(TAG, "[3.4] Create filter to catch audio data");
    record_filter_cfg_t record_cfg = DEFAULT_RECORD_FILTER_CONFIG();
    record_cfg.type = 0;     // 0 : heart, 1 : lung, 2 : all band
    record_cfg.channel = 1;
    record_filter = record_filter_init(&record_cfg);

    ESP_LOGI(TAG, "[3.5] Create i2s stream to write data to codec chip");
    i2s_stream_cfg_t i2s_cfg_wrt = I2S_STREAM_CFG_DEFAULT();
    i2s_cfg_wrt.type = AUDIO_STREAM_WRITER;
    i2s_cfg_wrt.std_cfg.clk_cfg.sample_rate_hz = 8000;
    i2s_stream_writer = i2s_stream_init(&i2s_cfg_wrt);

    ESP_LOGI(TAG, "[3.6] Register all elements to audio pipeline");
    audio_pipeline_register(pipeline, i2s_stream_reader, "i2s_read");
    // audio_pipeline_register(pipeline, equalizer, "equalizer");
    // audio_pipeline_register(pipeline, resampler, "resampler");
    audio_pipeline_register(pipeline, record_filter, "record_filter");
    audio_pipeline_register(pipeline, i2s_stream_writer, "i2s_write");

    ESP_LOGI(TAG, "[3.7] Link it together [codec_chip]-->i2s_stream_reader-->i2s_stream_writer-->[codec_chip]");
    const char *link_tag[3] = {"i2s_read", "record_filter", "i2s_write"};
    // const char *link_tag[2] = {"i2s_read",  "i2s_write"};
    audio_pipeline_link(pipeline, &link_tag[0], 3);

    ESP_LOGI(TAG, "[ 4 ] Set up  event listener");
    audio_event_iface_cfg_t evt_cfg = AUDIO_EVENT_IFACE_DEFAULT_CFG();
    audio_event_iface_handle_t evt = audio_event_iface_init(&evt_cfg);

    audio_hal_set_volume(board_handle->audio_hal, 100);

    ESP_LOGI(TAG, "[4.1] Listening event from all elements of pipeline");
    audio_pipeline_set_listener(pipeline, evt);

    ESP_LOGI(TAG, "[ 5 ] Start audio_pipeline");
    audio_pipeline_run(pipeline);

    ESP_LOGI(TAG, "[ 6 ] Listen for all pipeline events");
    while (1) {
        audio_event_iface_msg_t msg;
        esp_err_t ret = audio_event_iface_listen(evt, &msg, portMAX_DELAY);
        // esp_err_t ret = audio_event_iface_listen(evt, &msg, 500);   // 5 seconds 
        if (ret != ESP_OK) {
            ESP_LOGE(TAG, "[ * ] Event interface error : %d", ret);
            continue;
        }

        /* Stop when the last pipeline element (i2s_stream_writer in this case) receives stop event */
        if (msg.source_type == AUDIO_ELEMENT_TYPE_ELEMENT && msg.source == (void *) i2s_stream_writer
            && msg.cmd == AEL_MSG_CMD_REPORT_STATUS
            && (((int)msg.data == AEL_STATUS_STATE_STOPPED) || ((int)msg.data == AEL_STATUS_STATE_FINISHED))) {
            ESP_LOGW(TAG, "[ * ] Stop event received");
            break;
        }

        
    }

    ESP_LOGI(TAG, "[ 7 ] Stop audio_pipeline");
    audio_pipeline_stop(pipeline);
    audio_pipeline_wait_for_stop(pipeline);
    audio_pipeline_terminate(pipeline);

    audio_pipeline_unregister(pipeline, i2s_stream_reader);
    audio_pipeline_unregister(pipeline, i2s_stream_writer);

    /* Terminate the pipeline before removing the listener */
    audio_pipeline_remove_listener(pipeline);

    /* Make sure audio_pipeline_remove_listener & audio_event_iface_remove_listener are called before destroying event_iface */
    audio_event_iface_destroy(evt);

    /* Release all resources */
    audio_pipeline_deinit(pipeline);
    audio_element_deinit(i2s_stream_reader);
    audio_element_deinit(i2s_stream_writer);
}
